#include <map>
#include <algorithm>

namespace pyast {
namespace detail {

% for c in type_class_list:
<% Class = c.cppname %>

void* DeepCopyTraits<${Class}::underlying_type>::RecursivelyCopy(
    DeepCopyContext* ctx, void* v) {
    auto* u = CopyBytes(ctx->arena_, reinterpret_cast<${Class}::underlying_type>(v));

    switch (u->kind) {
        % for s in c.subclasses:
            case ${s.name}_kind:
            % for m in s.members:
                <% member = 'v.{}.{}'.format(s.name, m.name) %>
                % if m.is_ast():
                    u->${member} = ctx->DoCopy<${m.cpp_typename}>(u->${member});
                % elif m.is_object():
                    ctx->MaybeAddObject(u->${member});
                %endif
            % endfor
            break;
        % endfor
    }
    return u;
}

% endfor

% for c in product_class_list:
<% Class = c.cppname %>

void* DeepCopyTraits<${Class}::underlying_type>::RecursivelyCopy(
    DeepCopyContext* ctx, void* v) {
    auto* u = CopyBytes(ctx->arena_, reinterpret_cast<${Class}::underlying_type>(v));

    ## Since we use CopyBytes(), the old value of u can be taken as the source.
    ## Referencing only u can enhance cache locality.
    % for m in c.members:
        <% member = m.name %>
        % if m.is_ast():
            u->${member} = ctx->DoCopy<${m.cpp_typename}>(u->${member});
        % elif m.is_object():
            ctx->MaybeAddObject(u->${member});
        %endif
    % endfor

    return u;
}

% endfor
} // namespace detail

% for elm in seq_types:
    template class list<${elm.cppname}>;
% endfor

}
